<template>
	<view>
		<view id="allmap" class="allmap" />
		<view class="clock-btn">
			<!-- 注意：由于之前使用了 uview 按钮组件 u-button, click 事件无法触发 -->
			<button class="btn-box" @click="mapInstance.emitData">打 卡</button>
		</view>
		<u-toast ref="uToast"></u-toast>
		<u-notify ref="uNotify"></u-notify>
	</view>
</template>

<!-- https://blog.csdn.net/dai556688/article/details/123986098 -->
<!-- service层 逻辑线程 -->
<script>
	export default {
		methods: {
			// 计算坐标点之间的距离
			getDistance(lat1, lng1, lat2, lng2) {
				const EARTH_RADIUS = 6378.137;
				const radLat1 = this.rad(lat1);
				const radLat2 = this.rad(lat2);
				const a = radLat1 - radLat2;
				const b = this.rad(lng1) - this.rad(lng2);
				let s = 2.0 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2.0), 2.0) + Math.cos(radLat1) * Math.cos(
					radLat2) * Math.pow(Math.sin(b / 2.0), 2.0)));
				s = s * EARTH_RADIUS * 1000.0;
				return s;
			},
			rad(data) {
				return data * Math.PI / 180.0;
			},
			// 接收renderjs发回的数据
			receiveRenderData(val) {
				// console.log('renderjs返回的值-->', val);
				if (val.lng && val.lat) {
					const distance = Number(val.distance) - Number(val.radius)
					if (distance <= 0) {
						this.$refs.uNotify.show({
							type: 'primary',
							message: '打卡成功！坐标点为：' + val.lng + ', ' + val.lat,
							duration: 1000 * 3,
						})
					} else {
						this.$refs.uNotify.show({
							type: 'error',
							message: '不在打卡范围内！距离打卡点' + distance + '米',
							duration: 1000 * 3,
						})
					}
				} else {
					this.$refs.uToast.show({
						message: '请等待定位成功后再打卡！',
						type: 'warning',
						position: 'bottom'
					})
				}
			}
		}
	}
</script>

<!-- renderjs层 渲染线程 -->
<!-- 1.在renderjs层不能使用uni或其他框架的API，例如uni.request、uni.getlocation等等方法，需在原生层调用后触发监听将数据传入。
2.在APP端renderjs层的data与原生层的data互不相干。
3.this.$ownerInstance.callMethod方法必须通过点击事件执行。
4.地图方法都要写在renderjs层中，不能使用子组件。 -->
<script module="mapInstance" lang="renderjs">
	export default {
		data() {
			return {
				bdMapUrl: 'https://api.map.baidu.com/api?v=1.0&type=webgl&callback=initBMap&ak=',
				bdMapKey: 'Af6FfpOOZrHT1Ff2enuUKMZgjz4NfQ3W',
				map: null,
				centerPoint: {
					lng: 108.774386,
					lat: 34.262821,
					radius: 200
				},
				pointObj: {
					lng: null,
					lat: null,
					distance: 0,
					radius: 0
				},
				taskTimer: null
			}
		},
		created() {
			this.initMap()
			this.startTaskTimer()
		},
		beforeDestroy() {
			if (this.map) {
				this.map.destroy()
			}
			this.endTaskTimer()
		},
		methods: {
			// 定时任务
			startTaskTimer() {
				this.taskTimer = window.setInterval(() => {
					setTimeout(this.sdkLocation(), 0)
				}, 10000)
			},
			endTaskTimer() {
				clearInterval(this.taskTimer)
				this.taskTimer = null
			},
			bMapGLLoader() {
				return new Promise((resolve, reject) => {
					if (window.BMapGL) {
						resolve(window.BMapGL)
					} else {
						const script = document.createElement('script')
						script.type = 'text/javascript'
						script.src = this.bdMapUrl + this.bdMapKey
						script.async = true
						script.onerror = reject
						document.head.appendChild(script)
					}
					window.initBMap = function() {
						resolve(window.BMapGL)
					}
				})
			},
			// 初始化地图
			initMap() {
				this.$nextTick(() => {
					this.bMapGLLoader().then(BMapGL => {
						this.map = new BMapGL.Map('allmap')
						this.map.enableScrollWheelZoom(true) // 开启鼠标滚轮缩放
						const opts = {
							offset: new BMapGL.Size(10, 40)
						} // 偏移位置
						const scaleCtrl = new BMapGL.ScaleControl(opts);
						this.map.addControl(scaleCtrl); // 添加比例尺控件
						const zoomCtrl = new BMapGL.ZoomControl();
						this.map.addControl(zoomCtrl); // 添加缩放控件
						const cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
						this.map.addControl(cityCtrl);
						const navi3DCtrl = new BMapGL.NavigationControl3D({
							offset: new BMapGL.Size(0, 5),
						}); // 添加3D控件
						this.map.addControl(navi3DCtrl);
						const point = new BMapGL.Point(this.centerPoint.lng, this.centerPoint
							.lat); // 创建点坐标
						this.map.centerAndZoom(point, 17)
						this.map.clearOverlays();
						this.addCircle(point)
						this.sdkLocation() // 获取定位
						// this.webLocation() // 获取定位
					})
				})
			},
			// 获取定位: https://lbsyun.baidu.com/index.php?title=jspopularGL/guide/geoloaction
			// 状态码说明:
			// 6	ERR_PERMISSION_DENIED，没有权限，定位被拒绝
			// 2	ERR_POSITION_UNAVAILABLE，定位不可用
			// 8	ERR_POSITION_UNAVAILABLE，定位超时
			// 浏览器定位
			webLocation() {
				const __this = this
				const geolocation = new BMapGL.Geolocation();
				geolocation.getCurrentPosition(function(r) {
					if (this.getStatus() == BMAP_STATUS_SUCCESS) {
						// alert('您的位置：' + r.point.lng + ',' + r.point.lat);
						__this.pointObj.lng = r.point.lng
						__this.pointObj.lat = r.point.lat
						const point = new BMapGL.Point(r.point.lng, r.point.lat); // 创建点坐标
						__this.addMarker(point)
						__this.map.centerAndZoom(point, 17)
					} else {
						alert('定位失败，状态码为：' + this.getStatus());
					}
				});
			},
			// 定位SDK辅助定位
			sdkLocation() {
				const __this = this
				const geolocation = new BMapGL.Geolocation();
				// 开启SDK辅助定位
				geolocation.enableSDKLocation();
				geolocation.getCurrentPosition(function(r) {
					if (this.getStatus() == BMAP_STATUS_SUCCESS) {
						// alert('您的位置：' + r.point.lng + ',' + r.point.lat);
						__this.pointObj.lng = r.point.lng
						__this.pointObj.lat = r.point.lat
						const point = new BMapGL.Point(r.point.lng, r.point.lat); // 创建点坐标
						__this.addMarker(point)
						__this.map.centerAndZoom(point, 17)
					} else {
						alert('定位失败，状态码为：' + this.getStatus());
					}
				});
			},
			// 添加 marker 点
			addMarker(point) {
				this.removeOverlayById()
				const marker = new BMapGL.Marker(point)
				marker.id = 'currentLocation'
				this.map.addOverlay(marker)
			},
			// 移除地图指定覆盖点
			removeOverlayById() {
				const allOverlays = this.map.getOverlays()
				for (let i = 0; i < allOverlays.length; i++) {
					if (allOverlays[i].id && allOverlays[i].id === 'currentLocation') {
						this.map.removeOverlay(allOverlays[i])
					}
				}
			},
			// 添加圆形区域
			addCircle(point) {
				const circle = new BMapGL.Circle(point, this.centerPoint.radius, {
					fillColor: "blue",
					strokeWeight: 1,
					fillOpacity: 0.3,
					strokeOpacity: 0.3,
					// enableEditing: true // 可编辑：改变圆心位置半径等
				});
				this.map.addOverlay(circle);
			},
			// 获取两个坐标点之间的距离
			getDistanceByBD(lngA, latA, lngB, latB) {
				// 创建两个坐标点
				const point1 = new BMapGL.Point(lngA, latA);
				const point2 = new BMapGL.Point(lngB, latB);
				// 计算两点之间的直线距离
				const distance = this.map.getDistance(point1, point2);
				// console.log("两点之间的距离为：" + distance.toFixed(2) + " 米");
				return distance.toFixed(2)
			},
			// 发送数据到逻辑层
			emitData(e, ownerVm) {
				// 下面两个方法都可以
				this.pointObj.distance = this.getDistanceByBD(this.centerPoint.lng, this.centerPoint.lat, this.pointObj
					.lng, this.pointObj.lat)
				this.pointObj.radius = this.centerPoint.radius
				ownerVm.callMethod('receiveRenderData', this.pointObj)
				// this.$ownerInstance.callMethod('receiveRenderData', this.pointObj)
			}
		}
	}
</script>

<style>
	.allmap {
		width: 100%;
		height: 90%;
		position: absolute;
	}

	.clock-btn {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		margin: 40rpx 50rpx;
	}

	.btn-box {
		width: 100%;
		line-height: 78rpx;
		border-radius: 10rpx;
		text-align: center;
		font-weight: bold;
		color: #ffffff;
		background-color: #447aff;
	}
</style>